//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// OziExplorer WPT (waypoints) export.
//

# include "StdAfx.h"
# include "Save.h"
# include "Map.h"
# include "Status.h"
# include "SaveFileDlg.h"
# include "FileWriter.h"
# include "fast_floor.h"
# include "Globals.h"

class COziWptExport : public CMapSaver {
  public:
	virtual bool CanSave (const map_t & _map) {return true;}
	virtual bool Save (HANDLE _hFile, const char * _strFileName, const map_t & _map);

  private:
	bool _Save (HANDLE _hFile, const map_t & _map);
};

DECLARE_WPTRK_EXPORT (COziWptExport, "ozi-wpt", "wpt", "OziExplorer waypoints (*.wpt)");

bool COziWptExport::Save (HANDLE _hFile, const char * _strFileName, const map_t & _map) {
	if (_hFile) {
		return _Save (_hFile, _map);
	} else {
		//
		// Prepare default file name.
		//
		char strFileName [MAX_PATH + 1];
		::strncpy (strFileName, _strFileName, MAX_PATH);
		strFileName [MAX_PATH] = '\0';
		if (! SaveFileDlg ("wpt", "OziExplorer waypoints (*.wpt)\0*.wpt\0", strFileName))
			return false;

		//
		// Open the file.
		//
		const CFileForWrite hFile (strFileName);
		if (! hFile.IsValid ()) {
			ErrorMsgBox ("Can't create file:\n %s", strFileName);
			return false;
		}

		return _Save (hFile, _map);
	}
}

bool COziWptExport::_Save (HANDLE _hFile, const map_t & _map) {
	CFileWriter fw (_hFile);
	fw.SetFPrecision (6);

	//
	// Write the file.
	//
	SetProgressStatus (0);

	fw.WriteS (
		"OziExplorer Waypoint File Version 1.0\r\n"
		"WGS 84\r\n"
		"Reserved 2\r\n"
		"Reserved 3\r\n"
	);

	size_t cOrdinal = 1;

	size_t cRgn = 0;
	const size_t cRgns = _map.GetRgnCount ();
	for (size_t cKind = 0; cKind < rkMax; ++ cKind) {
		const layer_t & layer = _map.layers [cKind];
		const rgns_t & rgns = layer.rgns;
		for (rgns_t::const_iterator iRgn = rgns.begin (); iRgn != rgns.end (); ++ iRgn, ++ cRgn) {
			const rgn_t & rgn = * iRgn;
			if (rgn.IsDeleted () || ! rgn.IsWaypoint ())
				continue;

			const waypoint_info_t * const pWptExtra = rgn.pExtra->wtr.wpt ();
			assert (pWptExtra);

			// Save waypoint.
			for (size_t cOrigin = 0; cOrigin < rgn.origins.size (); ++ cOrigin) {
				const rgn_origin_t & origin = rgn.origins [cOrigin];
				if (origin.bDeleted)
					continue;

				// The ordinal.
				fw.WriteU (cOrdinal);
				fw.WriteC (',');

				// Name.
				if (! rgn.strLabel.empty ()) {
					for (size_t c = 0; c < rgn.strLabel.size (); ++ c) {
						const char ch = rgn.strLabel [c];
						fw.WriteC (ch == ',' ? 209 : ch);
					}
				} else
					fw.WriteU (cOrdinal);
				fw.WriteC (',');

				// Coordinates.
				fw.WriteF (origin.point.y);
				fw.WriteC (',');
				fw.WriteF (origin.point.x);
				fw.WriteC (',');

				// Time.
				if (pWptExtra->wFlags & waypoint_info_t::defTime)
					fw.WriteDF (pWptExtra->dtTime);
				else
					fw.WriteS (" ");
				fw.WriteC (',');

				// Symbol, Status, Display format.
				fw.WriteS ("0,1,3,");

				// Fg color.
				if (pWptExtra->wFlags & waypoint_info_t::defTextColor)
					fw.WriteU (pWptExtra->colText);
				else
					fw.WriteC ('0');
				fw.WriteC (',');

				// Bg color.
				if (pWptExtra->wFlags & waypoint_info_t::defBackColor)
					fw.WriteU (pWptExtra->colBack);
				else
					fw.WriteS ("65535");
				fw.WriteC (',');

				// Description.
				for (size_t c = 0; c < rgn.strComment.size () && c < 40; ++ c) {
					const char ch = rgn.strComment [c];
					fw.WriteC (ch == ',' ? 209 : ch);
				}

				// Pointer Direction, Garmin Display Format
				fw.WriteS (",0,0,");
				
				// Proximity Distance.
				if (pWptExtra->wFlags & waypoint_info_t::defProximity)
					fw.WriteU (fast_floor (pWptExtra->fProximity + .5f));
				else
					fw.WriteC ('0');
				fw.WriteC (',');

				// Altitude.
				int nAltitudeInFeet = -777;
				if (pWptExtra->wFlags & waypoint_info_t::defAltitude)
					nAltitudeInFeet = fast_floor (pWptExtra->fAltitude*c_feet_per_m + .5f);
				if (nAltitudeInFeet < 0)
					fw.WriteC ('-');
				fw.WriteU (::labs (nAltitudeInFeet));

				fw.WriteS ("\r\n");

				++ cOrdinal;
			}

			SetProgressStatus (fast_floor (100.f*cRgn/cRgns + .5f));
		}
	}

	fw.FlushBuffer ();

	SetProgressStatus (100);

	if (fw.GetOverflow ())
		ErrorMsgBox ("File has been written partialy.\nThis may be caused by disk overflow.");

	return true;
}
